//
//  AISSSDP.m
//  AISUPnP
//
//  Created by Ares on 1/26/15.
//  Copyright (c) 2015 Ares. All rights reserved.
//

#import "AISSSDP.h"
#import "GCDAsyncUdpSocket.h"
#import "AISSSDPMessage.h"

#define SSDP_MULTICAST_IP @"239.255.255.250"
#define SSDP_MULTICAST_PORT 1900

AISSSDP *gSSDPInstance = nil;

@interface AISSSDP()
{
    GCDAsyncUdpSocket *ssdpServerSocket;
}
@end

@implementation AISSSDP

+ (AISSSDP *)sharedInstance
{
    if (nil == gSSDPInstance)
    {
        gSSDPInstance = [[AISSSDP alloc] init];
    }
    return gSSDPInstance;
}

- (id)init
{
    self = [super init];
    if (nil != self)
    {
        [self initSSDPServer];
    }
    return self;
}

- (BOOL)initSSDPServer
{
    BOOL bInitRet = NO;
    do
    {
        BOOL bRet = NO;
        NSError *error;
        ssdpServerSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        if (nil == ssdpServerSocket)
        {
            break;
        }
        
        bRet = [ssdpServerSocket bindToPort:SSDP_MULTICAST_PORT error:&error];
        if (! bRet || nil != error)
        {
            NSLog(@"SSDP Bind Port Fail: %@", [error description]);
            break;
        }
        
        bRet = [ssdpServerSocket enableBroadcast:YES error:&error];
        if (! bRet || nil != error)
        {
            NSLog(@"SSDP Enable Broadcast Fail: %@", [error description]);
            break;
        }
        
        bRet = [ssdpServerSocket joinMulticastGroup:SSDP_MULTICAST_IP error:&error];
        if (! bRet || nil != error)
        {
            NSLog(@"SSDP Join Group Fail: %@", [error description]);
            break;
        }
        
        bRet = [ssdpServerSocket beginReceiving:&error];
        if (! bRet || nil != error)
        {
            NSLog(@"SSDP Begin Receive Fail: %@", [error description]);
            break;
        }
        
        bInitRet = YES;
    }
    while (0);
    
    return bInitRet;
}

#pragma mark Public Function For SSDP

- (BOOL)search
{
    BOOL bSearchRet = NO;
    NSString *strMSearch = [NSString stringWithFormat:@"M-SEARCH * HTTP/1.1\r\nContent-Length: 0\r\nST:ssdp:all\r\nMX: 2\r\nMAN: \"ssdp:discover\"\r\nHOST: %@:%d\r\n\r\n", SSDP_MULTICAST_IP, SSDP_MULTICAST_PORT];
    
    NSData *data = [strMSearch dataUsingEncoding:NSUTF8StringEncoding];
    
    [ssdpServerSocket sendData:data toHost:SSDP_MULTICAST_IP port:SSDP_MULTICAST_PORT withTimeout:-1 tag:0];
    
    return bSearchRet;
}

#pragma mark GCDAsyncUdpSocketDelegate

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
    if ([address isEqualToData:ssdpServerSocket.localAddress])
    {
        return;
    }
    
    NSString *host = nil;
    uint16_t port = 0;
    [GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];
    
    NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
    AISSSDPMessage *ssdpMessage = [[AISSSDPMessage alloc] initWithMessage:message fromHost:host andPort:port];
    
    if ([self.delegate respondsToSelector:@selector(ssdpReceivedMessage:)])
    {
        [self.delegate ssdpReceivedMessage:ssdpMessage];
    }
    
    return;
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
    NSLog(@"Data Sented.");
}


@end
